using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Application.Dtos;
using Joy.Erp.BasicArchives.Permissions;
using Joy.Erp.BasicArchives.Core.Filters;

namespace Joy.Erp.BasicArchives.ItemMasters
{
    [Authorize]
    public class BillOfMaterialsAppService : BasicArchivesAppService, IBillOfMaterialsAppService
    {
        protected IBillOfMaterialsRepository BillOfMaterialsRepository => LazyServiceProvider.LazyGetRequiredService<IBillOfMaterialsRepository>();
        protected BillOfMaterialsManager BillOfMaterialsManager => LazyServiceProvider.LazyGetRequiredService<BillOfMaterialsManager>();

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Query)]
        public async Task<BillOfMaterialsDto> GetAsync(Guid id)
        {
            return ObjectMapper.Map<BillOfMaterials, BillOfMaterialsDto>(
                await BillOfMaterialsRepository.GetAsync(id, true)
            );
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Query)]
        public async Task<BillOfMaterialsDto> FindAsync(string filter)
        {
            var entity = await BillOfMaterialsRepository.FindAsync(x => x.Code == filter);
            return ObjectMapper.Map<BillOfMaterials, BillOfMaterialsDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Query)]
        public async Task<BillOfMaterialsDto> FindBySourceKeyAsync(string sourceKey, string sourceType)
        {
            var entity = await BillOfMaterialsRepository.FindAsync(x => x.SourceKey == sourceKey && x.SourceType == sourceType);
            return ObjectMapper.Map<BillOfMaterials, BillOfMaterialsDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Query)]
        public async Task<PagedResultDto<BillOfMaterialsDto>> GetListAsync(FilterRequestDto input)
        {
            var totalCount = await BillOfMaterialsRepository.GetCountAsync(true);
            var list = await BillOfMaterialsRepository.GetPagedListAsync(input.Filter, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<BillOfMaterialsDto>(
                totalCount,
                ObjectMapper.Map<List<BillOfMaterials>, List<BillOfMaterialsDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Query)]
        public async Task<PagedResultDto<BillOfMaterialsDto>> QueryAsync(FilterGroupRequestDto input)
        {
            Expression<Func<BillOfMaterials, bool>> expression = null;
            if (input != null && input.FilterGroup != null)
            {
                expression = FilterConverter.Convert<BillOfMaterials>(input.FilterGroup);
            }

            var totalCount = await BillOfMaterialsRepository.GetCountAsync(expression, true);
            var list = await BillOfMaterialsRepository.GetPagedListAsync(expression, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<BillOfMaterialsDto>(
                totalCount,
                ObjectMapper.Map<List<BillOfMaterials>, List<BillOfMaterialsDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Query)]
        public virtual async Task<ListResultDto<BillOfMaterialsDto>> GetWithChildrenAsync(Guid parentId, bool recursive = false)
        {
            var currentDto = ObjectMapper.Map<BillOfMaterials, BillOfMaterialsDto>(
                await BillOfMaterialsRepository.GetAsync(parentId, true)
            );

            var list = ObjectMapper.Map<List<BillOfMaterials>, List<BillOfMaterialsDto>>(
                await BillOfMaterialsRepository.GetChildrenAsync(parentId, false, recursive)
            ).OrderBy(x => x.Code).ToList();

            list.Insert(0, currentDto);

            return new ListResultDto<BillOfMaterialsDto>(list);
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Query)]
        public virtual async Task<ListResultDto<BillOfMaterialsDto>> GetChildrenAsync(Guid? parentId, bool recursive = false)
        {
            var list = ObjectMapper.Map<List<BillOfMaterials>, List<BillOfMaterialsDto>>(
                await BillOfMaterialsRepository.GetChildrenAsync(parentId, false, recursive)
            ).OrderBy(x => x.Code).ToList();

            return new ListResultDto<BillOfMaterialsDto>(list);
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Create)]
        public async Task<BillOfMaterialsDto> CreateAsync(BillOfMaterialsCreateDto input)
        {
            var entity = ObjectMapper.Map<BillOfMaterialsCreateDto, BillOfMaterials>(input);
            input.MapExtraPropertiesTo(entity);

            await BillOfMaterialsManager.CreateAsync(entity, true);
            return await GetAsync(entity.Id);
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Update)]
        public async Task<BillOfMaterialsDto> UpdateAsync(Guid id, BillOfMaterialsUpdateDto input)
        {
            var entity = await BillOfMaterialsRepository.GetAsync(id);
            entity.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);

            ObjectMapper.Map(input, entity);

            input.MapExtraPropertiesTo(entity);

            await BillOfMaterialsManager.UpdateAsync(entity, true);
            return await GetAsync(entity.Id);
        }

        [Authorize(BasicArchivesPermissions.BillOfMaterials.Delete)]
        public async Task DeleteAsync(Guid id)
        {
            await BillOfMaterialsManager.DeleteAsync(id);
        }
    }
}